同樣是賦值,Verilog 共提供了兩種形式:blocking
、 nonblocking
。
Blocking 就是我們想像中的賦值,程式碼由上而下進行。但是, nonblocking 的程式碼是同時進行的,比起 blocking 還多了平行處理的概念。
這兩者在語法上有一個明顯的地方是 blocking 的賦值符號為 =
,而 nonblocking 的賦值符號則為 <=
。
接著,我們分別以 blocking 和 nonblocking 來實作以下的 pseudocode ,並用波形圖來看看結果吧!
// pseudocode
a, b, c, d, e = 1, 2, 5, 7, 3
a = 9
b = a
c = b
d = c
e = d
// Blocking
module tb;
reg [3:0] a, b, c, d, e;
initial begin
$dumpfile("Blocking.vcd");
$dumpvars(0, tb);
#1 a = 4'd1;
b = 4'd2;
c = 4'd5;
d = 4'd7;
e = 4'd3;
#2 a = 4'd9;
b = a;
c = b;
d = c;
e = d;
#5 $finish;
end
endmodule
在編譯與執行之前,我們不妨先想想結果是什麼!剛剛有提到 Blocking 的程式碼執行順序是由上而下執行,在 #1
(延遲一單位時間) 的部分,程式碼間無任何關聯,只是單純的賦值,因此這部分的結果不會受 Blocking 和 Nonblocking 影響。在 #2
(延遲二單位時間) 的部分,a 先設定為 9 ,接著 b 再設定為 a 的數值 9 , c 再設定為 b 的數值 9,以此類推。最終,我們可以得到所有變數的數值皆為 9 。
波形圖如下:
觀察波形圖要從兩個重點看起:時間刻度和變數數值。為了方便觀察時間刻度,我們特地給訂了延遲,因此我們要觀察的結果會是從第 3 秒開始。結果就和上述的推理一樣,所有變數數值都是 9 。
// Nonblocking
module tb;
reg [3:0] a, b, c, d, e;
initial begin
$dumpfile("Nonblocking.vcd");
$dumpvars(0, tb);
#1 a = 4'd1;
b = 4'd2;
c = 4'd5;
d = 4'd7;
e = 4'd3;
#2 a <= 4'd9;
b <= a;
c <= b;
d <= c;
e <= d;
#5 $finish;
end
endmodule
我們來想想結果會是什麼!結果和 Blocking 肯定不同,但是為什麼?
Nonblocking 的執行順序為所有程式碼同時起跑。 #1
的部分不影響,因為變數間沒有關聯性。關鍵在於第三秒後的變數數值 (#2
) 。第一行 a <= 4'd9
,a 設定為一個常數,blocking 和 nonblocking 不影響結果。第二行 b <= a
,b 的結果是 1 還是 9 呢?我們要這樣思考,執行 b <= a
時,a <= 4'd9
被執行了嗎?還沒喔。因為所有程式碼同時起跑,因此這時的 a 應為 1 ,所以 b 的數值為 1 。其餘的變數數值也是以這種方式推理而來。
波形圖如下:
Blocking 和 Nonblocking 在 Verilog 中是相當重要的議題。當這個議題遇上了時脈,過程又會更加複雜。但是透過這兩種模式,我們可以彈性的建構出不同的電路,因此這是相當重要的!